﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.SharePoint;
using AgileShare.Framework.SiteProvisioning.Helpers;
using AgileShare.Framework.Library.Helpers;
using AgileShare.Framework.Core;

namespace AgileShare.Framework.SiteProvisioning.Definitions
{
	/// <summary>
	/// 
	/// </summary>
	public class SiteStructureDefinition
	{
		/// <summary>
		/// Gets or sets the fields.
		/// </summary>
		/// <value>
		/// The fields.
		/// </value>
		public FieldDefinitionCollection FieldDefinitions { get; set; }

		/// <summary>
		/// Gets or sets the content types.
		/// </summary>
		/// <value>
		/// The content types.
		/// </value>
		public ContentTypeDefinitionCollection ContentTypeDefinitions { get; set; }

		/// <summary>
		/// Gets or sets the list template definitions.
		/// </summary>
		/// <value>
		/// The list template definitions.
		/// </value>
		public ListTemplateDefinitionCollection ListTemplateDefinitions { get; set; }

		/// <summary>
		/// Gets or sets the list instance definitions.
		/// </summary>
		/// <value>
		/// The list instance definitions.
		/// </value>
		public ListInstanceDefinitionCollection ListInstanceDefinitions { get; set; }

		/// <summary>
		/// Gets or sets the site definitions.
		/// </summary>
		/// <value>
		/// The site definitions.
		/// </value>
		public SiteDefinitionCollection SiteDefinitions { get; set; }

		/// <summary>
		/// Initializes a new instance of the <see cref="SiteStructureDefinition" /> class.
		/// </summary>
		public SiteStructureDefinition()
		{
			this.FieldDefinitions = new FieldDefinitionCollection();
			this.ContentTypeDefinitions = new ContentTypeDefinitionCollection();
			this.ListTemplateDefinitions = new ListTemplateDefinitionCollection();
			this.ListInstanceDefinitions = new ListInstanceDefinitionCollection();
			this.SiteDefinitions = new SiteDefinitionCollection();
		}		

		/// <summary>
		/// Deploys the specified site.
		/// </summary>
		/// <param name="site">The site.</param>
		/// <param name="update">if set to <c>true</c> [update].</param>
		/// <param name="pushChangesToLists">if set to <c>true</c> [push changes to lists].</param>
		public void Deploy(SPSite site, bool update = false, bool pushChangesToLists = false)
		{
			SPWeb web = site.RootWeb;

			DateTime startTime = DateTime.Now;

			// Site Definition Start
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Started Deploying Site Definition to Site '{0}' at {1}.", site.Url, DateTime.Now);

			// Fields
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Started Deploying Fields to Site '{0}' at {1}.", site.Url, DateTime.Now);

			FieldDefinitionHelper.EnsureFields(this.FieldDefinitions, web.Fields, update, pushChangesToLists);

			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Ended Deploying Fields to Site '{0}' at {1}.", site.Url, DateTime.Now);

			// Content Types
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Started Deploying Content Types to Site '{0}' at {1}.", site.Url, DateTime.Now);

			ContentTypeDefinitionHelper.EnsureContentTypes(this.ContentTypeDefinitions, site, update, pushChangesToLists);

			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Ended Deploying Content Types to Site '{0}' at {1}.", site.Url, DateTime.Now);

			// List Templates
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Started Deploying List Templates to Site '{0}' at {1}.", site.Url, DateTime.Now);

			ListDefinitionHelper.EnsureListTemplates(this.ListTemplateDefinitions, site, update);

			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Ended Deploying List Templates to Site '{0}' at {1}.", site.Url, DateTime.Now);

			// List Instances
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Started Deploying List Instances to Site '{0}' at {1}.", site.Url, DateTime.Now);

			ListDefinitionHelper.EnsureLists(this.ListInstanceDefinitions, web, update);

			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Ended Deploying List Instances to Site '{0}' at {1}.", site.Url, DateTime.Now);

			// Sites
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Started Deploying Sites to Site '{0}' at {1}.", site.Url, DateTime.Now);

			SiteDefinitionHelper.EnsureSites(this.SiteDefinitions, web, update);

			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Ended Deploying Sites to Site '{0}' at {1}.", site.Url, DateTime.Now);

			// Site Definition End
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Monitorable,
				"Ended Deploying Site Definition to Site '{0}' at {1}. Total time: {2}", site.Url, DateTime.Now, (DateTime.Now - startTime).TotalMinutes);
		}		

		/// <summary>
		/// Removes all.
		/// </summary>
		/// <param name="site">The site.</param>
		public void RemoveAll(SPSite site)
		{
			SPWeb web = site.RootWeb;

			SPListHelper.DeleteListsByRelativeUrl(web, this.ListInstanceDefinitions.RelativeUrls);
			SPListHelper.DeleteListsByTitle(web, this.ListInstanceDefinitions.Titles);
			SPListHelper.DeleteListTemplates(site, this.ListTemplateDefinitions.TemplateNames);
			SPContentTypeHelper.DeleteContentTypes(site, false, this.ContentTypeDefinitions.ContentTypeIds);
			SPFieldHelper.DeleteFields(site, false, this.FieldDefinitions.FieldIds);
		}
	}
}
